package edu.spbsu.nonsm00th.qdiff;

import edu.spbsu.nonsm00th.model.Point;
import java.util.ArrayList;
import java.util.List;

/**
 * Quasidifferential representation class.
 *
 * @author mukhadin
 */
public class Quasidiff {

    private List<Point> subdiff;
    private List<Point> superdiff;

    public Quasidiff(List<Point> subdiff, List<Point> superdiff) {
        this.subdiff = subdiff;
        this.superdiff = superdiff;
    }

    public List<Point> getSubdiff() {
        return subdiff;
    }

    public void setSubdiff(List<Point> subdiff) {
        this.subdiff = subdiff;
    }

    public List<Point> getSuperdiff() {
        return superdiff;
    }

    public void setSuperdiff(List<Point> superdiff) {
        this.superdiff = superdiff;
    }

    /**
     * Multiply quasidifferential by constant.
     * If
     * D = [A,B]
     * then
     * cD = [cA,cB], c>=0
     * cD = [cB,cA], c<0
     *
     * @param c the constant multiplier
     */
    public Quasidiff multiply(double c) {
        for (Point p : subdiff) {
            for (int i = 0; i < p.getDimension(); i++) {
                p.setXi(i, p.getXi(i) * c);
            }
        }
        for (Point p : superdiff) {
            for (int i = 0; i < p.getDimension(); i++) {
                p.setXi(i, p.getXi(i) * c);
            }
        }
        if (0 > c) {
            List<Point> temp = subdiff;
            subdiff = superdiff;
            superdiff = temp;
        }
        return this;
    }

    /**
     * Adding another quasidifferential.
     * If
     * D1 = [A1,B1]
     * D2 = [A2,B2]
     * then
     * D1 + D2 = [A1+A2,B1+B2]
     *
     * @param q quasidifferential to add
     */
    public Quasidiff add(Quasidiff q) {
        List<Point> subsum = new ArrayList<Point>();
        for (Point p1 : subdiff) {
            for (Point p2 : q.subdiff) {
                subsum.add(sum(p1, p2));
            }
        }

        List<Point> supersum = new ArrayList<Point>();
        for (Point p1 : superdiff) {
            for (Point p2 : q.superdiff) {
                subsum.add(sum(p1, p2));
            }
        }
        //TODO: replace by convexhull
        return this;
    }

    /**
     * Returns the adding result of points in space. Dimensions are always same.
     *
     * TODO: maybe better move this method to some utility class.
     *
     * @param p1 point
     * @param p2 point
     * @return result point
     */
    private Point sum(Point p1, Point p2) {
        double[] x = new double[p1.getDimension()];
        for (int i = 0; i < p1.getDimension(); i++) {
            x[i] = p1.getXi(i) + p2.getXi(i);
        }
        return new Point(x);
    }
}
